/*
* 710605420@qq.com
*/
#include "CoroutineMathine.h"
#include <vector>
#include <future>

namespace BoostCorountine2
{

	CoroutineMathine::CoroutineMathine()
	{
// 		std::promise<void> result;
// 		Thread = std::make_unique<std::thread>([this, &result] {
// 			result.set_value();
// 
// 			});
// 		result.get_future().get();
	}

	CoroutineMathine::~CoroutineMathine()
	{
		StopAllCoroutine();
	}
	Coroutine* CoroutineMathine::StartCoroutine(Enumerator InEnumerator)
	{
		CoroPull Pull(InEnumerator);
		if (Pull)
		{
			return InsertCoroutine(new Coroutine(Pull));
		}
		return nullptr;
	}

	Coroutine* CoroutineMathine::InsertCoroutine(Coroutine* Coro)
	{
		YieldInstruction* Yi = Coro->GetYieldReturn();
		if (Yi == nullptr || Yi->Type == TYPEID(Break))
		{
			return Coro;
		}

		Coroutines.push_back(Coro);
		return Coro;

	}

	void CoroutineMathine::StopCoroutine(Coroutine* Coro)
	{
		
// 		if (std::find(Coroutines.begin(), Coroutines.end(), Coro) != Coroutines.end())
// 		{
// 			std::remove(std::begin(Coroutines), std::end(Coroutines), Coro);
// 		}
// 		if (std::find(CoroutinesCopy.begin(), CoroutinesCopy.end(), Coro) != CoroutinesCopy.end())
// 		{
// 			std::remove(std::begin(CoroutinesCopy), std::end(CoroutinesCopy), Coro);
// 		}
		if (Coro)
		{
			Coro->Cancel();
			YieldInstruction* YieldReturnPtr = nullptr;
			while (Coro != nullptr)
			{
				Coro->Cancel();
				YieldReturnPtr = Coro->GetYieldReturn();
				if (YieldReturnPtr && YieldReturnPtr->Type == TYPEID(Coroutine))
				{
					Coro = static_cast<Coroutine*>(YieldReturnPtr);
				}
				else
				{
					Coro = nullptr;
				}
			}

			
		}
		
		
	}

	void CoroutineMathine::StopAllCoroutine()
	{
		for (Coroutine* CoroutinePtr : Coroutines)
		{
			if (CoroutinePtr)
			{
				delete CoroutinePtr;
				CoroutinePtr = nullptr;
			}
		}
		Coroutines.clear();

		for (Coroutine* CoroutinePtr : CoroutinesCopy)
		{
			if (CoroutinePtr)
			{
				delete CoroutinePtr;
				CoroutinePtr = nullptr;
			}
		}
		CoroutinesCopy.clear();
	}

	bool CoroutineMathine::HasCoroutines()
	{
		return !Coroutines.empty();
	}

	void CoroutineMathine::ResumeCoroutines()
	{
		CoroutinesCopy.clear();
		CoroutinesCopy.swap(Coroutines);

		for (Coroutine* CoroutinePtr : CoroutinesCopy)
		{
			if (CoroutinePtr && CoroutinePtr->IsAlive())
			{
				YieldInstruction* YieldReturnPtr = CoroutinePtr->GetYieldReturn();
				if (YieldReturnPtr)
				{
					if (!YieldReturnPtr->IsAlive())
					{
						if (YieldReturnPtr->Type != TYPEID(Coroutine))
						{
							delete YieldReturnPtr;
							YieldReturnPtr = nullptr;
						}

						CoroutinePtr->Resume();
						Coroutines.push_back(CoroutinePtr);
						
					}
					else
					{
						Coroutines.push_back(CoroutinePtr);
					}
					
				}else
				{ 
					//delete CoroutinePtr;
					CoroutinePtr = nullptr;
				}
			}
			else
			{
				if (CoroutinePtr)
				{
					delete CoroutinePtr;
					CoroutinePtr = nullptr;
				}
			}
			
			
		}
		CoroutinesCopy.clear();
	}

}

